home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / Open Transport / OT 1.1 GM / Open Transport SDK / Open Tpt Client Developer / Samples / AppleTalk / PAPSample.cp < prev    next >
Encoding:
Text File  |  1996-02-13  |  19.0 KB  |  884 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PAPSample.cp
  3.  
  4.     Contains:    Sample demonstration program for PAP
  5.  
  6.     Copyright:    © 1993-1995 by Apple Computer, Inc., all rights reserved.
  7.  
  8. */
  9.  
  10. #ifndef __OPENTPTGLOBALNEW__
  11. #include <OpenTptGlobalNew.h>
  12. #endif
  13. #ifndef __OPENTPTAPPLETALK__
  14. #include <OpenTptAppleTalk.h>
  15. #endif
  16. #ifndef __ATALKSAMPLEUTILS__
  17. #include "ATalkSampleUtils.h"
  18. #endif
  19. #ifndef __STDIO__
  20. #include <stdio.h>
  21. #endif
  22. #ifndef __EVENTS__
  23. #include <Events.h>
  24. #endif
  25. #ifndef __TEXTUTILS__
  26. #include <TextUtils.h>
  27. #endif
  28.  
  29. #define byName                1
  30. #define byAddr                0
  31.  
  32. const size_t kMaxRecv = 5000;          /*Max received data*/ 
  33. const size_t kMaxSend = 4096;          /*Max send data*/ 
  34. UInt8         gIncomingBuffer[kMaxRecv];
  35.  
  36. #if byName
  37. TNetbuf     gDestName;
  38. #endif
  39.  
  40. DDPAddress    gDestAddr;
  41.  
  42. const size_t    kMaxReplyBufLen    = (512 * 8) + 4;
  43.  
  44. TEndpoint*     gEp            = NULL;
  45. TEndpoint*    gStatusEp    = NULL;
  46. Boolean     gConnectFlag = false;
  47. OSStatus     gConnectErr = 0;
  48. Boolean        gFlowControl = false;
  49. Boolean        gDone = false;
  50. Boolean        gEOF = false;
  51. char        gReadBuf[kMaxSend];
  52. OTLIFO        gEventList;
  53.  
  54. UInt16        gStatSequence = 0;
  55. Boolean        gStatusAvailable = false;
  56. Boolean        gReceivedOrdRel = false;
  57. UInt8         gReplyBuffer[kMaxReplyBufLen];
  58. UInt8         gCurrentStatus[kMaxReplyBufLen]={0};
  59. UInt32        gNextStatusTime = 0;
  60. /*******************************************************************************
  61. ** Structures
  62. ********************************************************************************/
  63.  
  64. class TOTEventItem
  65. {
  66.     public:
  67.                     inline TOTEventItem(void* ref, unsigned long code,
  68.                                          OTResult result, void* cookie)
  69.                     {
  70.                         fRef        = ref;
  71.                         fCode        = code;
  72.                         fResult        = result;
  73.                         fCookie        = cookie;
  74.                     };
  75.     OTLink            fLink;
  76.     void*            fRef;
  77.     unsigned long    fCode;
  78.     OTResult        fResult;
  79.     void*            fCookie;
  80. };
  81.  
  82. /*******************************************************************************
  83. ** Prototypes
  84. ********************************************************************************/
  85.  
  86. pascal    void        EventHandler(void*, OTEventCode, OTResult, void*);
  87.         OTResult    DoReceive(TEndpoint*, unsigned char*);
  88.         OTResult    DoRequestStatus(TEndpoint *ep, Boolean useName = false);
  89.         void        DoReadUReplies(TEndpoint*);
  90.  
  91. /*******************************************************************************
  92. ** EventHandler
  93. **  The event handler can be called at times when it is not safe to do console I/O,
  94. **  so this routine takes the event and jams it on a list to be handled when
  95. **  we know it's safe to print informative messages
  96. ********************************************************************************/
  97.  
  98. pascal void EventHandler(void* contextPtr, OTEventCode code,
  99.                                         OTResult result, void* cookie)
  100. {    
  101.     TOTEventItem* item = new TOTEventItem(contextPtr, code, result, cookie);
  102.  
  103.     if (item == NULL)
  104.     {
  105.         DebugStr("\pPAPTest: UniversalEventHandler -- could not allocate event structure");
  106.     }
  107.     else
  108.     {
  109.         gEventList.Enqueue(&item->fLink);
  110.     }
  111. }
  112.  
  113.  
  114.  
  115. /*******************************************************************************
  116. ** PollEventList
  117. **   This routine picks up the events received by EventHandler and processes them
  118. ********************************************************************************/
  119.  
  120. OSStatus PollEventList()
  121. {
  122.     OSStatus err = kOTNoError;
  123.     while ( true )
  124.     {
  125.         OTLink* link = OTReverseList(gEventList.StealList());
  126.         
  127.         if ( link == NULL )
  128.             break;
  129.             
  130.         while ( link != NULL )
  131.         {
  132.             TOTEventItem* item = OTGetLinkObject(link, TOTEventItem, fLink);
  133.  
  134.             link = link->fNext;
  135.         
  136.             OTResult result = item->fResult;
  137.             void* cookie = item->fCookie;
  138.             int epNum  = (int)item->fRef;
  139.             if (epNum < 0 || epNum > 1)
  140.             {
  141.                 fprintf(stderr, "PAPTest: PollEventList, Got bad refnum in event record");
  142.                 delete item;
  143.                 continue;
  144.             }
  145.  
  146.             TEndpoint* ep = epNum ? gStatusEp : gEp;
  147.  
  148.             switch (item->fCode )
  149.             {
  150.                 
  151.                 case T_DATA:
  152.                 {
  153.                     DoReceive(ep, gIncomingBuffer);
  154.                     fprintf(stderr, "Recieved Message: %s\n", gIncomingBuffer);
  155.                     break;
  156.                 }
  157.                 
  158.                 case T_CONNECT:
  159.                 {
  160. #if byName        
  161.                     TCall rcvCall;
  162.                     rcvCall.addr.maxlen = sizeof gDestAddr;
  163.                     rcvCall.addr.buf    = (UInt8*)&gDestAddr;
  164.                     rcvCall.opt.len        = 0;
  165.                     rcvCall.udata.len    = 0;
  166.                     OSStatus err = ep->RcvConnect(&rcvCall);
  167.                     
  168.                     gDestAddr.SetSocket(128); // set this to the SLS
  169. #endif
  170. #if byAddr
  171.                     OSStatus err = ep->RcvConnect(NULL);
  172. #endif        
  173.                     if ( err != kOTNoError && err != kOTNoDataErr )
  174.                     {
  175.                         gConnectErr = err;
  176.                         DebugStr("\pPAPSample: RcvConnect returns an error!;g");
  177.                     }
  178.                     else
  179.                         gConnectFlag = true;
  180.         
  181.                     break;
  182.                 }
  183.                 
  184.                 case T_GODATA:
  185.                 {
  186.                     gFlowControl = false; // indicate that flow control has lifted
  187.                     break;
  188.                 }
  189.                     
  190.                 case T_ORDREL:
  191.                 {
  192.                     err = ep->RcvOrderlyDisconnect();
  193.                     if ( err != kOTNoError )
  194.                     {
  195.                         DebugStr("\pRcvOrderlyDisconnect failed.;g");
  196.                     }
  197.                     gReceivedOrdRel = true;
  198.                     break;
  199.                 }
  200.                 
  201.                 case T_DISCONNECT:
  202.                 {
  203.                     TBind* bindReq = (TBind*)cookie;
  204.                     if ( bindReq != NULL )            // A connect is rejected
  205.                     {
  206.                         DebugStr("\pConnection attempt failed. Doing RcvDisconnect.;g");
  207.                         ep->RcvDisconnect(NULL);
  208.                         gConnectErr = -2; // special constant
  209.                     }
  210.                     break;
  211.                 }
  212.                 
  213.                 case T_REPLY :
  214.                 {
  215.                     DoReadUReplies(ep);
  216.                     break;
  217.                 }
  218.                     
  219.                 
  220.                 default:
  221.                 {
  222.                     DebugStr("\pPAPSample: Unexpected Event!;g");
  223.                     break;
  224.                 }
  225.             }
  226.         }
  227.     }
  228.     return err;
  229. }
  230.  
  231. /*******************************************************************************
  232. ** DoBind
  233. ********************************************************************************/
  234.  
  235. OSStatus DoBind(TEndpoint* ep, unsigned char socket, unsigned char type)
  236. {
  237.     OSStatus err = kOTNoError;
  238.     
  239.     DDPAddress    addr;
  240.     addr.Init(0, 0, socket, type);        // Source address & type
  241.     
  242.     TBind                    req;
  243.     req.addr.buf    = (UInt8*)&addr;
  244.     req.addr.len    = kDDPAddressLength;
  245.     req.qlen        = 0;
  246.     
  247.     TBind                    ret;
  248.     
  249.     ret.addr.buf    = (UInt8*)&addr;
  250.     ret.addr.maxlen    = sizeof(addr);
  251.  
  252.     fprintf(stderr, "Doing Bind\n");
  253.     //
  254.     // Try to bind
  255.     // 
  256.     err = ep->Bind(&req, &ret);
  257.     if ( err != kOTNoError )
  258.     {
  259.         fprintf(stderr, "PAPSample: DoBind returns error %d\n", err);
  260.         return err;
  261.     }
  262.  
  263.     fprintf(stderr, "Bound address = ");
  264.     ShowDDPAddress(&addr);
  265.     fprintf(stderr, "\n");
  266.     fprintf(stderr, "Bound queue len is %d\n", ret.qlen);
  267.  
  268.     fprintf(stderr, "After Bind, ");
  269.     ShowEndpointState(ep, "");
  270.  
  271.     return err;
  272. }
  273.  
  274. /*******************************************************************************
  275. ** DoConnect
  276. ********************************************************************************/
  277.  
  278. OSStatus DoConnect(TEndpoint* ep)
  279. {
  280.     TCall theCall;
  281. #if byAddr
  282.     theCall.addr.buf    = (UInt8*)&gDestAddr;
  283.     theCall.addr.len    = kDDPAddressLength;
  284. #endif
  285. #if byName
  286.     theCall.addr.buf    = gDestName.buf;
  287.     theCall.addr.len    = gDestName.len;
  288. #endif
  289.     theCall.opt.len        = 0;
  290.     theCall.udata.len    = 0;
  291.  
  292.     OSStatus err = ep->Connect(&theCall, NULL);
  293.     if ( err != kOTNoError && err != kOTNoDataErr )
  294.     {
  295.         fprintf(stderr, "Connect() returns %d\n", err);
  296.         if ( err == kOTLookErr )
  297.         {
  298.             
  299.             fprintf(stderr, "Calling RcvDisconnect()...");
  300.             OSStatus err = ep->RcvDisconnect(NULL);
  301.             fprintf(stderr, "returns %d\n", err);
  302.         }
  303.     }
  304.     else
  305.     {
  306.         err = kOTNoError;
  307.         Boolean flag = false;
  308.         while ( !gConnectFlag && !gConnectErr  && !(flag = Button()) )
  309.         {
  310.             OTIdle();
  311.             PollEventList();
  312.         }
  313.         
  314.         if ( flag )
  315.             err = -1; //%%% for now
  316.         else
  317.             err = gConnectErr;
  318.  
  319.      }
  320.     return err;
  321. }
  322.  
  323. /*******************************************************************************
  324. ** DoRead
  325. ********************************************************************************/
  326.  
  327. OSStatus DoReadData( FILE* fp, char **pp, size_t* countPtr)
  328. {
  329.     if ( *countPtr == 0 )
  330.     {
  331.         size_t numread = fread(gReadBuf, 1, sizeof(gReadBuf), fp); 
  332.         if ( numread < 0 )
  333.         {
  334.             fprintf(stderr, "Error %s reading file\n", numread);
  335.             return (OSStatus)numread;
  336.         }
  337.         gEOF = (numread < sizeof(gReadBuf));
  338.         *countPtr = numread;
  339.         *pp = gReadBuf;
  340.     }
  341. }
  342.         
  343.  
  344. /*******************************************************************************
  345. ** DoSend
  346. ********************************************************************************/
  347.  
  348. OSStatus DoSend(TEndpoint* ep, char **pp, size_t* countPtr)
  349. {
  350. if (*countPtr <= 0)DebugStr("\pBad Count!");
  351.     
  352.     if (gFlowControl || gDone)
  353.         return 0;
  354.         
  355.         
  356.     putc('.', stderr);
  357.             
  358.     OTResult result = ep->Snd(*pp, *countPtr, 0 );
  359.  
  360.     if ( result == kOTFlowErr )
  361.     {
  362.         fprintf(stderr, "Snd(%08X) flow controlled on NORMAL channel\n", ep);
  363.         gFlowControl = true;
  364.         return 1;
  365.     }
  366.  
  367.     if ( result == kOTLookErr || result == kOTOutStateErr  ||
  368.          result == kEAGAINErr )
  369.         return 1;
  370.  
  371.     if ( result < 0 )
  372.     {
  373.         fprintf(stderr, "Snd(%08X) fails with %d\n", ep, result);
  374.     }
  375.     else
  376.     {
  377.         (*countPtr) -= result;
  378.         (*pp) += result;
  379.         result = 0;
  380.     }
  381.     
  382.     gDone = (gEOF && (*countPtr == 0));
  383.     
  384.     return (OSStatus)result;
  385. }
  386.  
  387.  
  388. /*******************************************************************************
  389. ** DoReceive
  390. ********************************************************************************/
  391.  
  392. OTResult DoReceive(TEndpoint* ep, UInt8* buffer)
  393. {
  394.     OTFlags        flags = 0;
  395.     OTResult    result;
  396.     
  397.     while (true)
  398.     {
  399.  
  400.         result = ep->Rcv(buffer, kMaxRecv, &flags);
  401.         if ( result < 0 )
  402.         {
  403.             if ( result == kOTLookErr )
  404.             {
  405.                 OTResult res = ep->Look();
  406.                 fprintf(stderr, "Rcv() returns LOOK, Look returns %d\n", res);
  407.                 if ( res == T_DATA )
  408.                     continue;
  409.             }
  410.             else if ( result != kOTNoDataErr )
  411.                 fprintf(stderr, "Rcv() returns %d\n", result);
  412.         }
  413.         
  414.     return result;
  415.     }
  416. }
  417. /*******************************************************************************
  418. ** DoReadUReplies
  419. ********************************************************************************/
  420.  
  421. void DoReadUReplies(TEndpoint* atpEp)
  422. {
  423.  
  424.     OSStatus    err;
  425.     OTFlags        flags;
  426.     
  427.     while ( true )
  428.     {
  429.         TUnitReply    reply;
  430.         
  431.         reply.opt.maxlen    = 0;
  432.         reply.udata.maxlen    = sizeof(gReplyBuffer);
  433.         reply.udata.buf        = gReplyBuffer;
  434.         
  435.         err = atpEp->RcvUReply(&reply, &flags);
  436.         
  437.         if ( err != kOTNoError )
  438.         {
  439.             if ( err == kOTNoDataErr )
  440.                 return;
  441.             if ( err != kETIMEDOUTErr )
  442.             {
  443.                 fprintf(stderr, "\nOTRcvUReply: returned error %d\n", err);
  444.                 return;
  445.             }
  446.         }
  447.         
  448.         // If this is really the reply to our last request, save it.
  449.         if ( reply.sequence == gStatSequence )
  450.         {
  451.             gStatusAvailable = true;
  452.             if (!EqualString(gCurrentStatus, gReplyBuffer+8, true, true) ) 
  453.             {
  454.                 fprintf(stderr, "\n>> %#s\n", gReplyBuffer+8);
  455.                 memcpy(gCurrentStatus, gReplyBuffer+8, reply.udata.len); 
  456.             }
  457.         }
  458.         
  459.     }
  460. }
  461.  
  462. /*******************************************************************************
  463. ** CreatePAPEndpoint
  464. ********************************************************************************/
  465.  
  466. TEndpoint* CreatePAPEndpoint()
  467. {
  468.     TEndpoint*    ep = NULL;
  469.     OSStatus    err = kOTNoError;
  470.  
  471.     do
  472.     {
  473.         //
  474.         // Create a PAP
  475.         //
  476.         ep = OTOpenEndpoint(OTCreateConfiguration(kPAPName), 0, NULL, &err);
  477.  
  478.         if ( ep == NULL || err != kOTNoError )
  479.         {
  480.             ep = NULL;
  481.             fprintf(stderr,"ERROR: OpenEndpoint(\"pap\") failed with %d\n", err);
  482.             break;
  483.         }
  484.         ep->SetSynchronous();
  485.  
  486.         //
  487.         // Install notifier we're going to use for testing
  488.         //
  489.         err = ep->InstallNotifier(EventHandler, NULL);
  490.         if ( err != kOTNoError )
  491.         {
  492.             fprintf(stderr, "ERROR: InstallNotifier() failed with %d\n", err);
  493.             break;
  494.         }
  495.  
  496.         ShowFullEndpointData(ep);
  497.         
  498.         return ep;
  499.  
  500.     } while ( false );
  501.     
  502.     if ( ep != NULL )
  503.         ep->Close();
  504.     
  505.     return NULL;
  506. }
  507.  
  508. /*******************************************************************************
  509. ** CreateATPEndpoint
  510. **  Note that this will be a synchronous endpoint, so we don't need a notifier.
  511. ********************************************************************************/
  512.  
  513. TEndpoint* CreateATPEndpoint()
  514. {
  515.     TEndpoint*    ep = NULL;
  516.     OSStatus    err = kOTNoError;
  517.  
  518.     do
  519.     {
  520.         //
  521.         // Create a PAP
  522.         //
  523.         ep = OTOpenEndpoint(OTCreateConfiguration(kATPName), 0, NULL, &err);
  524.  
  525.         if ( ep == NULL || err != kOTNoError )
  526.         {
  527.             ep = NULL;
  528.             fprintf(stderr,"ERROR: OpenEndpoint(\"atp\") failed with %d\n", err);
  529.             break;
  530.         }
  531.         ep->SetSynchronous();
  532.  
  533.         //
  534.         // Install notifier we're going to use for testing
  535.         //
  536.         err = ep->InstallNotifier(EventHandler, (void*)1);
  537.         if ( err != kOTNoError )
  538.         {
  539.             fprintf(stderr, "ERROR: InstallNotifier() failed with %d\n", err);
  540.             break;
  541.         }
  542.  
  543.         
  544.         return ep;
  545.  
  546.     } while ( false );
  547.     
  548.     if ( ep != NULL )
  549.         ep->Close();
  550.     
  551.     return NULL;
  552. }
  553.  
  554. /*******************************************************************************
  555. ** DoRequestStatus
  556. ********************************************************************************/
  557. OTResult DoRequestStatus(TEndpoint *ep, Boolean useName)
  558. {
  559.     static UInt8 requestMsg[4] = {0, 8, 0, 0};
  560.     
  561.     TUnitRequest theReq;
  562.  
  563.     if ( useName )
  564.     {
  565.         theReq.addr.buf    = gDestName.buf;
  566.         theReq.addr.len    = gDestName.len;
  567.     }
  568.     else
  569.     {
  570.         theReq.addr.buf    = (UInt8*)&gDestAddr;
  571.         theReq.addr.len    = kDDPAddressLength;
  572.     }
  573.     theReq.opt.len        = 0;
  574.     theReq.udata.buf    = requestMsg;
  575.     theReq.udata.len    = sizeof requestMsg;
  576.     
  577.     theReq.sequence        = ++gStatSequence;
  578.     
  579.     gStatusAvailable     = false;
  580.     
  581.     OTResult err = ep->SndURequest(&theReq, 0);
  582.     
  583.     gNextStatusTime = TickCount()+60;
  584.     
  585.     if ( err != kOTNoError )
  586.         fprintf(stderr, "SndURequest returns %d\n", err);
  587.     
  588.     return err;
  589. }
  590.     
  591.  
  592. /*******************************************************************************
  593. ** DoTest
  594. ********************************************************************************/
  595.  
  596. void DoTest()
  597. {
  598.     OSStatus err = kOTNoError;
  599.     
  600.     FILE *fp=NULL;
  601.  
  602.     do
  603.     {
  604.     /*    -------------------------------------------------------------------------
  605.         Create endpoint.
  606.         ------------------------------------------------------------------------- */
  607.  
  608.         gEp = CreatePAPEndpoint();
  609.          if ( gEp == NULL )
  610.          {
  611.              fprintf(stderr, "PAPSample: CreatePAPEndpoint for endpoint failed.\n", err);
  612.              break;
  613.          }
  614.         
  615.         /*-------------------------------------------------------------------------
  616.         Bind endpoint.
  617.         ------------------------------------------------------------------------- */
  618.  
  619.         UInt8 socket    = 48;
  620.         UInt8 type        = 3;
  621.         
  622.         err = DoBind(gEp, socket, type);
  623.         if ( err != kOTNoError )
  624.         {
  625.             fprintf(stderr, "PAPSample: bind of PAP endpoint #1 failed.\n");
  626.             break;
  627.         }
  628.  
  629.         gEp->SetAsynchronous();
  630.         
  631.     /*    -------------------------------------------------------------------------
  632.         In order to get status from the printer, we have to use ATP. So let's open
  633.         and ATP endpoint.
  634.         ------------------------------------------------------------------------- */    
  635.  
  636.         gStatusEp = CreateATPEndpoint();
  637.          if ( gStatusEp == NULL )
  638.          {
  639.              fprintf(stderr, "PAPSample: CreateATPEndpoint for endpoint failed .\n", err);
  640.              break;
  641.          }
  642.         
  643.         /*-------------------------------------------------------------------------
  644.         Bind status endpoint.
  645.         ------------------------------------------------------------------------- */
  646.  
  647.         socket        = 0;
  648.         type        = 3;
  649.         
  650.         err = DoBind(gStatusEp, socket, type);
  651.         if ( err != kOTNoError )
  652.         {
  653.             fprintf(stderr, "PAPSample: bind of ATP endpoint #1 failed.\n");
  654.             break;
  655.         }
  656.  
  657.         gEp->SetAsynchronous();
  658.         
  659.     /*    -------------------------------------------------------------------------
  660.         Run the test.
  661.         ------------------------------------------------------------------------- */
  662.         do
  663.         {
  664.             char fileName[256];
  665.             fprintf(stderr, "Enter name of input file:\n");
  666.             while ( true )
  667.             {
  668.                 gets(fileName);
  669.                 if ( fileName[0] != 0 )
  670.                     break;
  671.             }
  672.             
  673.             fp = fopen(fileName, "r");
  674.             if (fp == NULL)
  675.             {
  676.                 fprintf(stderr, "Couldn't open file %s\n", fileName);
  677.                 break;
  678.             }
  679.             
  680. #if byName
  681.             NBPAddress addr;
  682.             char addrBuf[64];
  683.         
  684.             fprintf(stderr, "Enter name to send to in form 'name:type@zone'\n");
  685.             while ( true )
  686.             {
  687.                 gets(addrBuf);
  688.                 if ( addrBuf[0] != 0 )
  689.                     break;
  690.             }
  691.             gDestName.buf    = (UInt8*)&addr;
  692.             gDestName.len    = addr.Init(addrBuf);
  693. #endif            
  694. #if byAddr
  695.             int net, node, socket;
  696.             
  697.             fprintf(stderr, "Enter the target network: ");
  698.             scanf("%x", &net);
  699.             fprintf(stderr, "Enter the target node: ");
  700.             scanf("%x", &node);
  701.             fprintf(stderr, "Enter the target socket: ");
  702.             scanf("%x", &socket);
  703.     
  704.             gDestAddr.Init((UInt16)net, (UInt8)node, (UInt8)socket);
  705.             fprintf(stderr, "Target net node socket: %.4x  %.2x %.2x \n",net, node, socket);
  706. #endif    
  707.             //
  708.             // See what our status looks like
  709.             //
  710.             DoRequestStatus(gStatusEp, true);    
  711.             //
  712.             // Connect
  713.             //
  714.             err = DoConnect(gEp);
  715.             if ( err != kOTNoError )
  716.             {
  717.                 if ( err == -2 )
  718.                     fprintf(stderr, "Connection attempt failed\n");
  719.                 else
  720.                     fprintf(stderr, "DoConnect returned %d\n", err);
  721.                 break;
  722.             }    
  723.             //
  724.             // See what our status looks like
  725.             //
  726.             DoRequestStatus(gStatusEp);    
  727.             
  728.         
  729.             //
  730.             // Try to Send some data
  731.             // 
  732.             fprintf(stderr, "Copying File:\n");
  733.             
  734.             gFlowControl = false;
  735.             gDone = false;
  736.             
  737.             size_t count = 0;
  738.             char *bufPtr = NULL;
  739.             
  740.             do
  741.             {
  742.                 err = DoReadData(fp, &bufPtr, &count);
  743.                 if ( err < 0 )
  744.                     break;
  745.                 
  746.                 err = DoSend(gEp, &bufPtr, &count);
  747.                 if ( err < 0 )
  748.                     break;
  749.                 
  750.                 OTIdle();
  751.                 if (TickCount() >= gNextStatusTime)
  752.                     DoRequestStatus(gStatusEp);
  753.                 PollEventList();
  754.             
  755.             } while ( !gDone );
  756.             fprintf(stderr, "Write Complete\n");
  757.  
  758.         } while ( false );
  759.         
  760.         if ( gConnectFlag )
  761.         {
  762.             fprintf(stderr, "Press mouse to disconnect\n");
  763.             while ( !Button() )                    // Wait for  mouse button
  764.             {
  765.                 OTIdle();
  766.                 if (TickCount() >= gNextStatusTime)
  767.                     DoRequestStatus(gStatusEp);
  768.                 PollEventList();
  769.             }
  770.             while ( Button() )                    // Wait 'til it's released
  771.             {
  772.                 OTIdle();
  773.                 if (TickCount() >= gNextStatusTime)
  774.                     DoRequestStatus(gStatusEp);
  775.                 PollEventList();
  776.             }
  777.                 
  778.             //
  779.             // Send Orderly Release
  780.             // 
  781.             gEp->SetSynchronous();
  782.             fprintf(stderr, "About to Disconnect()\n");
  783.             gReceivedOrdRel = false;
  784.             err = gEp->SndOrderlyDisconnect();
  785.             if ( err != kOTNoError )
  786.             {
  787.                 if ( err == kOTLookErr )
  788.                 {
  789.                     fprintf(stderr,
  790.                         "SndOrderlyDisconnect(%d) returns with kLook\n", gEp);
  791.                     err = 0;
  792.                 }
  793.                 else
  794.                     fprintf(stderr,
  795.                         "SndOrderlyDisconnect(%d) fails with %d\n", gEp, err);
  796.             }
  797.         
  798.             while( !gReceivedOrdRel && !Button() )
  799.             {
  800.                 OTIdle();
  801.                 if (TickCount() >= gNextStatusTime)
  802.                     DoRequestStatus(gStatusEp);
  803.                 PollEventList();
  804.             }
  805.             ShowEndpointState(gEp, "");
  806.         }
  807.  
  808.         
  809.         //
  810.         // Unbind
  811.         //
  812.         fprintf(stderr, "About to Unbind()\n");
  813.         err = gEp->Unbind();
  814.         if ( err != kOTNoError )
  815.         {
  816.             fprintf(stderr, "ERROR: Unbind(pap) returned %d\n", err);
  817.             break;
  818.         }
  819.         ShowEndpointState(gEp, "");
  820.         
  821.         err = gStatusEp->Unbind();
  822.         if ( err != kOTNoError )
  823.         {
  824.             fprintf(stderr, "ERROR: Unbind(atp) returned %d\n", err);
  825.             break;
  826.         }
  827.         ShowEndpointState(gStatusEp, "");
  828.         
  829.     } while (false);
  830.  
  831.     //
  832.     // Get rid of endpoint.
  833.     //
  834.     if ( gStatusEp != NULL )
  835.     {
  836.         gStatusEp->RemoveNotifier();
  837.         gStatusEp->Close();
  838.     }    //
  839.     // Get rid of endpoint.
  840.     //
  841.     if ( gStatusEp != NULL )
  842.     {
  843.         gStatusEp->RemoveNotifier();
  844.         gStatusEp->Close();
  845.     }
  846.     
  847.     //
  848.     // close our file
  849.     //
  850.     if ( fp != NULL )
  851.         fclose(fp);
  852.  
  853. }
  854.  
  855. /*******************************************************************************
  856. ** Initialize OpenTransport and call DoTest function
  857. ********************************************************************************/
  858.  
  859. main(int, char**) 
  860. {
  861.     InitGraf(&qd.thePort);                    // initialize quickdraw so we can use regions
  862.  
  863.     fprintf(stderr, "PAPSample showing usage of PAP.\n\n");
  864.     //
  865.     // Initialize Open Transport
  866.     //
  867.     InitOpenTransport();
  868.     //
  869.     // Run the test
  870.     //
  871.     DoTest();
  872.     //
  873.     // Close Open Transport.
  874.     // Not strictly necessary since it patches _ExitToShell and will
  875.     // clean us up anyway.
  876.     //
  877.     CloseOpenTransport();
  878.     
  879.     fprintf(stderr, "\n\nDone\n");
  880.         
  881.     return 0;
  882. };
  883.  
  884.